package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xyy.saas.payment.adpater.yzh.constant.ConfigPath;
import com.xyy.saas.payment.adpater.yzh.util.DESUtil;
import com.xyy.saas.payment.adpater.yzh.util.RSAUtil;
import com.xyy.saas.payment.adpater.yzh.vo.*;
import com.xyy.saas.payment.cores.bo.YzhBankPayBo;
import com.xyy.saas.payment.cores.bo.YzhwxPayBo;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.cores.vo.YzhBankPayVo;
import com.xyy.saas.payment.cores.vo.YzhwxPayVo;
import com.xyy.saas.payment.manager.BankPayManager;
import com.xyy.saas.payment.manager.WXPayManager;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.util.Map;

/**
 * @Author lina
 * @Description
 * @Date 2022/3/9
 **/
@Slf4j
@RestController
@RequestMapping(value = {"/api/yzh"})
public class YzhController {
    private static final String AND = "&";
    private static final String EQUAL = "=";

    @Resource
    private BankPayManager bankPayManager;
    @Resource
    private WXPayManager wxPayManager;

    /**
     * 云账户银行卡支付结果通知
     * @param message
     * @return
     */
    @RequestMapping(value = "/bank/pay/notify", method = RequestMethod.POST)
    public String bankPayNotify(@RequestBody String message) {
        log.info("YzhNotifyController#bankPayNotify ,message={}", message);
        try {
            BackNotifyMessage backNotifyMessage = decodeResp(message, ConfigPath.HY_BANK_PAY);
            if (null == backNotifyMessage) {
                log.error("YzhNotifyController#bankPayNotify 解析回调参数异常！message={}", message);
                return ConfigPath.YZH_NOTIFY_FAIL;
            }
            boolean dealResult = bankPayManager.dealYzhBankPayCallback(backNotifyMessage);
            log.info("YzhNotifyController#bankPayNotify backNotifyMessage={}, dealResult={}",
                    JSONUtils.toJSON(backNotifyMessage), dealResult);
            return dealResult ? ConfigPath.YZH_NOTIFY_SUCCESS : ConfigPath.YZH_NOTIFY_FAIL;
        } catch (Exception e) {
            log.error("YzhNotifyController#bankPayNotify 回调处理异常！message={}", message, e);
            return ConfigPath.YZH_NOTIFY_FAIL;
        }
    }

    /**
     * 云账户微信支付结果通知
     * @param message
     * @return
     */
    @RequestMapping(value = "/wx/pay/notify", method = RequestMethod.POST)
    public String wxPayNotify(@RequestBody String message) {
        log.info("YzhNotifyController#wxPayNotify ,message={}", message);

        try {
            BackNotifyMessage backNotifyMessage = decodeResp(message, ConfigPath.HY_WX_PAY);

            if(null == backNotifyMessage) {
                log.error("YzhNotifyController#wxPayNotify 解析回调参数异常！message={}", message);
                return ConfigPath.YZH_NOTIFY_FAIL;
            }

            boolean dealResult = wxPayManager.dealNotify(backNotifyMessage);
            log.info("YzhNotifyController#wxPayNotify backNotifyMessage={}, dealResult={}",
                    JSONUtils.toJSON(backNotifyMessage), dealResult);
            return dealResult ? ConfigPath.YZH_NOTIFY_SUCCESS : ConfigPath.YZH_NOTIFY_FAIL;
        }
        catch(Exception ex) {
            log.error("YzhNotifyController#wxPayNotify 回调处理异常！message=" + message, ex);
            return ConfigPath.YZH_NOTIFY_FAIL;
        }
    }

    /**
     * 请求银行卡支付
     * @param yzhBankPayVo
     * @return
     */
    @RequestMapping(value = "/bank/pay/apply", method = RequestMethod.POST)
    public String doBankPay(@RequestBody YzhBankPayVo yzhBankPayVo) {
        log.info("YzhNotifyController#doBankPay ,yzhBankPayVo={}", yzhBankPayVo);
        try {
            ResultVO<YzhBankPayBo> yzhBankPayBoResultVO = bankPayManager.bankPay(yzhBankPayVo);
            return JSONUtils.toJSON(yzhBankPayBoResultVO);
        } catch (Exception e) {
            log.error("YzhNotifyController#doBankPay 请求支付！yzhBankPayVo={}", yzhBankPayVo, e);
            return "查询异常";
        }
    }

    /**
     * 请求微信支付
     * @param yzhwxPayVo
     * @return
     */
    @RequestMapping(value = "/wx/pay/apply", method = RequestMethod.POST)
    public String doWXPay(@RequestBody YzhwxPayVo yzhwxPayVo) throws Exception {
        log.info("YzhNotifyController#doWXPay ,yzhwxPayVo={}", yzhwxPayVo);
        try {
            ResultVO<YzhwxPayBo> resultVO = wxPayManager.wxPay(yzhwxPayVo, StringUtils.EMPTY);
            return JSONUtils.toJSON(resultVO);
        }
        catch(Exception e) {
            log.error("YzhNotifyController#doWXPay 请求支付！yzhwxPayVo={}", yzhwxPayVo, e);
            throw e;
        }
    }

    /**
     * 查询银行卡支付状态
     * @param payNo
     * @return
     */
    @RequestMapping(value = "/pay/query", method = RequestMethod.POST)
    public String bankPayQuery(String payNo, String method) {
        log.info("YzhNotifyController#bankPayQuery ,payNo={}, method={}", payNo, method);
        try {
            BackNotifyData result = bankPayManager.queryPayResultFromYzh(payNo, method);
            return JSONUtils.toJSON(result);
        } catch (Exception e) {
            log.error("YzhNotifyController#bankPayQuery 查询异常！payNo={}", payNo, e);
            return "查询异常";
        }
    }

    private static BackNotifyMessage decodeResp(String message, String method) {
        try {
            NotifyResponse notifyResponse = parseResp(URLDecoder.decode(message,"utf-8"), NotifyResponse.class);

            if(null == notifyResponse) {
                log.error("YzhNotifyController#decodeResp 解析回调参数为空, message={}, method={}", message, method);
                return null;
            }

            // 回调数据验签
            if(!RSAUtil.verify(notifyResponse.getPlain(method), notifyResponse.getSign(),
                    ApolloUtil.getProperty(ConfigPath.HY_WX_PAY.equals(method) ? ConfigPath.WX_YZH_RSA_PUBLIC_KEY : ConfigPath.YZH_RSA_PUBLIC_KEY)))
            {
                log.error("YzhNotifyController#decodeResp RSA验签失败，请确认公钥是否正确！message={}", message);
                return null;
            }

            log.info("YzhNotifyController#decodeResp ,message={}， notifyResponse：{}", message, JSONObject.toJSONString(notifyResponse));

            // 3DES解密
            return JSONObject.parseObject(DESUtil.decode(notifyResponse.getData(), method), BackNotifyMessage.class);
        }
        catch(Exception e) {
            log.error("YzhNotifyController#decodeResp 参数解码失败！message={}", message, e);
            return null;
        }
    }

    private static <T> T parseResp(String message, Class clazz) {
        if (StringUtils.isEmpty(message)) {
            return null;
        }

        Map<String, String> data = Maps.newHashMap();
        for(String element:message.split(AND)){
            String[] sub = element.split(EQUAL, 2);
            data.put(sub[0], sub[1]);
        }
        return JSONObject.parseObject(JSONObject.toJSONString(data), (Type) clazz);
    }
}
